package com.thprojects.myphotomemories.view.components;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class DrawableImageView extends ImageView implements OnTouchListener {

	final float mStroke = 5f;
    ArrayList<Draw> mDrawings = new ArrayList<Draw>();
    Draw mCurDrawing;
    Paint mPaint = new Paint();
	int mCurColor = Color.rgb(255, 0, 0);
	OnDrawListener mOdl;
	Rect mBoundingRect;


    public DrawableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setFocusable(true);
        setFocusableInTouchMode(true);
        
        this.setOnTouchListener(this);
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(mStroke);
        
        
        
    }
    
    public void setOnDrawListener(OnDrawListener odl){
    	mOdl = odl;
    }
    
    public int getColor(){
    	return mCurColor;
    }
    
    public void setColor(int color){
    	mCurColor = color;
    }
    
    public void setBoundingRect(Rect r){
    	Rect oldRect = mBoundingRect;
    	mBoundingRect = r;

    	if (oldRect == null) return;
    	
    	//transform drawing coords
    	float bmpRatio = (float)mBoundingRect.height()/oldRect.height();
    	
		for (Draw draw : mDrawings) {
			
			List<Point> newPoints = new ArrayList<Point>();
       	        	
        	for (Point pp: draw.mPoints){
        		Point p = new Point();
        		p.x = bmpRatio*(pp.x-oldRect.left)+r.left;
            	p.y = bmpRatio*(pp.y-oldRect.top)+r.top;
            	newPoints.add(p);
        	}
        	draw.mPoints = newPoints;
        }
		
    }
    
    public void undo(){
    	if (mDrawings.size() == 0) return;
    	mDrawings.remove(mDrawings.size()-1);
    	invalidate();
    }

    public void clear(){
    	mDrawings = new ArrayList<Draw>();
    	invalidate();
    }
    
    public boolean isClean(){
    	return mDrawings.size() == 0;
    }
    
    public Bitmap drawOriginalBitmap(Bitmap bmp, float bmpRatio, int dx, int dy){
    	Bitmap res = bmp.copy(Bitmap.Config.ARGB_8888, true);
    	Paint paint = new Paint();
    	paint.setAntiAlias(true);
    	paint.setStrokeWidth(mStroke*bmpRatio);
    	
    	Canvas canvas = new Canvas(res);
    	Log.d("MPM", "c.w="+canvas.getWidth()+", c.h="+canvas.getHeight());
    	Log.d("MPM", "bmpRatio = "+bmpRatio);
    	
    	for (Draw draw : mDrawings) {
    		paint.setColor(draw.mColor); 
        	
        	if (draw.mPoints.size() == 0) continue;
        	
        	//first point transformed
        	Point p = new Point();
        	p.x = (draw.mPoints.get(0).x - dx)*bmpRatio;
        	p.y = (draw.mPoints.get(0).y - dy)*bmpRatio;
        	
        	canvas.drawCircle(p.x, p.y, mStroke*bmpRatio/2, paint);
        	
        	for (int i=1; i<draw.mPoints.size(); i++){
        		//Point p1 = draw.mPoints.get(i-1);
        		Point p1 = new Point();
        		p1.x = (draw.mPoints.get(i-1).x - dx)*bmpRatio;
            	p1.y = (draw.mPoints.get(i-1).y - dy)*bmpRatio;
        		//Point p2 = draw.mPoints.get(i);
            	Point p2 = new Point();
            	p2.x = (draw.mPoints.get(i).x - dx)*bmpRatio;
            	p2.y = (draw.mPoints.get(i).y - dy)*bmpRatio;
        		canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint);
        		canvas.drawCircle(p2.x, p2.y, mStroke*bmpRatio/2, paint);
        	}
        }

    	
    	return res;
    }
    
    @Override
    public void onDraw(Canvas canvas) {
    	super.onDraw(canvas);
    	canvas.clipRect(mBoundingRect);
    	for (Draw draw : mDrawings) {
    		mPaint.setColor(draw.mColor); 
    		
    		Log.d("MPM", "drawing");
        	
        	if (draw.mPoints.size() == 0) continue;
        	
        	canvas.drawCircle(draw.mPoints.get(0).x, draw.mPoints.get(0).y, mStroke/2, mPaint);
        	Log.d("MPM", draw.mPoints.get(0).toString());
        	
        	for (int i=1; i<draw.mPoints.size(); i++){
        		Log.d("MPM", draw.mPoints.get(i).toString());
        		Point p1 = draw.mPoints.get(i-1);
        		Point p2 = draw.mPoints.get(i);
        		canvas.drawLine(p1.x, p1.y, p2.x, p2.y, mPaint);
        		canvas.drawCircle(p2.x, p2.y, mStroke/2, mPaint);
        	}
        }
    }
    

    public boolean onTouch(View view, MotionEvent event) {
    	if(event.getAction() == MotionEvent.ACTION_DOWN){
    		mCurDrawing = new Draw(mCurColor);
    		mDrawings.add(mCurDrawing);
    		mOdl.OnDraw(); 
    	}
    	addPoint(event);
        return true;
    }
    
    private void addPoint(MotionEvent event){
    	Point point = new Point();
        point.x = event.getX();
        point.y = event.getY();
        mCurDrawing.mPoints.add(point);
        invalidate();
    }

	public void save(Bundle outState) {
		outState.putParcelableArrayList("drawings", mDrawings);
		outState.putParcelable("curDrawing", mCurDrawing);
		outState.putInt("curColor", mCurColor);
		outState.putInt("oldHeight", mBoundingRect.height());
		outState.putInt("oldLeft", mBoundingRect.left);
		outState.putInt("oldTop", mBoundingRect.top);
		outState.putInt("oldRight", mBoundingRect.right);
		outState.putInt("oldBottom", mBoundingRect.bottom);
	}

	public void restore(Bundle savedState) {
		mDrawings = savedState.getParcelableArrayList("drawings");
		mCurDrawing = savedState.getParcelable("curDrawing");
		mCurColor = savedState.getInt("curColor");
		int oldLeft = savedState.getInt("oldLeft");
		int oldTop = savedState.getInt("oldTop");
		int oldRight = savedState.getInt("oldRight");
		int oldBottom = savedState.getInt("oldBottom");
		mBoundingRect = new Rect(oldLeft, oldTop, oldRight, oldBottom);
	}
}

class Point implements Parcelable{
    float x, y;
    
    public Point(){}
    
    public Point(Parcel in){
    	x = in.readFloat();
    	y = in.readFloat();
    }
    
    public void writeToParcel(Parcel out, int arg1){
    	out.writeFloat(x);
    	out.writeFloat(y);
    }

    // this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
    public static final Parcelable.Creator<Point> CREATOR = new Parcelable.Creator<Point>() {
        public Point createFromParcel(Parcel in) {
            return new Point(in);
        }

        public Point[] newArray(int size) {
            return new Point[size];
        }
    };
    
    public int describeContents() {
		return 0;
	}
    
    @Override
    public String toString() {
        return "("+x + ", " + y+")";
    }

	
}

class Draw implements Parcelable{
	int mColor;
	List<Point> mPoints;
	
	Draw(int color){
		this.mColor = color;
		mPoints = new ArrayList<Point>();
	}
	
    
    public Draw(Parcel in){
    	mColor = in.readInt();
    	mPoints = new ArrayList<Point>(); 
    	in.readTypedList(mPoints, Point.CREATOR);
    }
    
    public void writeToParcel(Parcel out, int arg1){
    	out.writeInt(mColor);
    	out.writeTypedList(mPoints);
    }

    // this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
    public static final Parcelable.Creator<Draw> CREATOR = new Parcelable.Creator<Draw>() {
        public Draw createFromParcel(Parcel in) {
            return new Draw(in);
        }

        public Draw[] newArray(int size) {
            return new Draw[size];
        }
    };
    
    public int describeContents() {
		return 0;
	}
}
